package com.springsummer.information.green.beans;


import com.springsummer.information.green.io.ClassPathResource;

import java.io.InputStream;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class NormalPropertyResolver implements PropertyResolver {

    //https://liaoxuefeng.com/books/summerframework/ioc/property-resolver/index.html


    private Map<String, String> propsMap = new LinkedHashMap<>(256);

    public NormalPropertyResolver() {
    }

    public NormalPropertyResolver(Properties props) {
        // 存入环境变量:
        this.propsMap.putAll(System.getenv());
        // 存入Properties:
        Set<String> names = props.stringPropertyNames();
        for (String name : names) {
            this.propsMap.put(name, props.getProperty(name));
        }
    }

    public NormalPropertyResolver loadFromProperties(Properties properties) {
        return new NormalPropertyResolver(properties);
    }

    public NormalPropertyResolver loadFromApplicationProps() {
        Properties appProperties = new Properties();
        ClassPathResource classPathResource = new ClassPathResource("application.properties");
        try (InputStream inputStream = classPathResource.getInputStream();) {
            // Java标准库读取properties文件:
            //Properties props = new Properties();
            //props.load(fileInput); // 文件输入流
            // 构造PropertyResolver:
            //PropertyResolver pr = new PropertyResolver(props);

            appProperties.load(inputStream);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        NormalPropertyResolver propertyResolver = new NormalPropertyResolver(appProperties);
        return propertyResolver;
    }

    public Set<String> getPropertyNames() {
        return propsMap.keySet();
    }

    @Override
    public boolean containsProperty(String name) {
        return propsMap.containsKey(name);
    }

    @Override
    public String getProperty(String keyname) {
        return getPropertyInternal(keyname, null);
    }

    private String getPropertyInternal(String keyname, String defaultVal) {
        PropertyKeyExpr keyExpr = parsePropertyKeyExpr(keyname);

        if (keyExpr != null) { //keyname含有${}
            if (keyExpr.getDefaultValue() != null) {
                // 带默认值查询:
                return getPropertyWithDefaultVal(keyExpr.getKey(), keyExpr.getDefaultValue());
            } else {
                // 不带默认值查询:
                if (defaultVal != null) {
                    return getPropertyWithDefaultVal(keyExpr.getKey(), defaultVal);
                }

                return getRequiredProperty(keyExpr.getKey());
            }
        }

        //keyname
        String propVal = null;
        if (defaultVal != null) {
            propVal = getPropertyWithDefaultVal(keyname, defaultVal);
        } else {
            propVal = getRequiredProperty(keyname);
        }

        return propVal;
    }

    private String getPropertyWithDefaultVal(String keyname, String defaultValue) {
        String propValue = propsMap.get(keyname);
        if (propValue != null) {
            return propValue;
        }
        return defaultValue;
    }

    protected String getRequiredProperty(String key) {
        return propsMap.get(key);
    }

    @Override
    public String getProperty(String name, String defaultValue) {
        return getPropertyInternal(name, defaultValue);
    }

    @Override
    public <T> T getProperty(String name, Class<T> targetType) {
        String normalPropVal = getProperty(name);
        if (normalPropVal != null) {
            //convert
            return convertPropVal(normalPropVal, targetType);
        }
        return (T) normalPropVal;
    }

    protected <T> T convertPropVal(String source, Class<T> targetType) {
        if (Integer.class == targetType) {
            return (T) Integer.valueOf(source);
        }
        if (String.class == targetType) {
            return (T) String.valueOf(source);
        }
        if (Double.class == targetType) {
            return (T) Double.valueOf(source);
        }
        if (Boolean.class == targetType) {
            return (T) Boolean.valueOf(source);
        }
        if (BigDecimal.class == targetType) {
            return (T) new BigDecimal(source);
        }
        return (T) source;
    }

    public static class PropertyKeyExpr {

        private String key;

        private String defaultValue;

        public PropertyKeyExpr() {
        }

        public PropertyKeyExpr(String key, String defaultValue) {
            this.key = key;
            this.defaultValue = defaultValue;
        }

        public String getKey() {
            return key;
        }

        public void setKey(String key) {
            this.key = key;
        }

        public String getDefaultValue() {
            return defaultValue;
        }

        public void setDefaultValue(String defaultValue) {
            this.defaultValue = defaultValue;
        }

    }

    public PropertyKeyExpr parsePropertyKeyExpr(String key) {
        if (key.startsWith("${") && key.endsWith("}")) {
            // 是否存在defaultValue?
            int n = key.indexOf(':');
            if (n == (-1)) {
                // 没有defaultValue: ${key}
                String k = key.substring(2, key.length() - 1);
                return new PropertyKeyExpr(k, null);
            } else {
                // 有defaultValue: ${key:default}
                String k = key.substring(2, n);
                return new PropertyKeyExpr(k, key.substring(n + 1, key.length() - 1));
            }
        }
        return null;
    }

    public PropertyKeyExpr resolvePlaceholder(String key) {
        if (key.startsWith("${") && key.endsWith("}")) {
            // 是否存在defaultValue?
            int n = key.indexOf(':');
            if (n == (-1)) {
                // 没有defaultValue: ${key}
                String k = key.substring(2, key.length() - 1);
                return new PropertyKeyExpr(k, null);
            } else {
                // 有defaultValue: ${key:default}
                String k = key.substring(2, n);
                return new PropertyKeyExpr(k, key.substring(n + 1, key.length() - 1));
            }
        }
        return null;
    }

}
